# coding:utf8
"""
需求：
    检查本机ipv4地址，并发送邮件到lee_cq@icould.com。
        如果本次核对结果和上一次相同，忽略。
Version:
    v1.0 - 2019/10/13
        1.完成需求。
"""
import socket, time, smtplib
from os.path import exists, getsize
from os import mkdir, remove
from email.mime.text import MIMEText
from email.header import Header
from traceback import format_exc

# 定义常量 - Constant
if not exists('./_sup'): mkdir('./_sup')                      # make sure the Dir has './_sup'.
f_ipv4 = './_sup/ipv4.ini'                                   # Configuration file - The File save last address of IPv4.
f_logRepeat = './_sup/LogRepeat.txt'
f_logSent = './_sup/LogSent.txt'                             # 保存日志的文件
f_logError = './_sup/ErrorTraceback.log'                     # 保存错误回朔的文件
f_infoEmailQq = './_sup/info_qqEmail.ini'                        # 保存-邮件配置信息
f_infoEmail126 = './_sup/info_126Email.ini'
ipv4 = socket.gethostbyname(socket.gethostname())           # Get IPv4 address.
nowTime = time.strftime("%Y-%m-%d %H:%M", time.localtime())  # Now Time
_str126 = """###注意字符串中禁止包含空格。可以不包含引号。
####删除文件后可以重新生成。
    receiver = 'lee_cq@icloud.com'      # 收件人 (List or Str)
    sender = 'leecq_01@126.com'         # 发件人
    mailHost = "smtp.126.com"           # SMTP 服务器
    mailUser = "leecq_01@126.com"       # User
    mailPasswd = "lichao1234567890"     # Passwd"""
_strQq = """###注意字符串中禁止包含空格。可以不包含引号。
####删除文件后可以重新生成。
    receiver = 'lee_cq@icloud.com'      # 收件人 (List or Str)
    sender = '1491311784@qq.com'         # 发件人
    mailHost = "smtp.qq.com"           # SMTP 服务器
    # mailPort = 465
    mailUser = "1491311784@qq.com"       # User
    mailPasswd = "gfpvtffnkoyigjhb"     # Passwd"""
_striCloud = """###注意字符串中禁止包含空格。可以不包含引号。
####删除文件后可以重新生成。
    receiver = 'lee_cq@icloud.com'      # 收件人 (List or Str)
    sender = 'lee_cq@icloud.com'         # 发件人
    mailHost = "smtp.mail.me.com"           # SMTP 服务器
    # mailPort = 587
    mailUser = "lee_cq@icloud.com"       # User
    mailPasswd = "woal-wfji-egkk-vpvw"     # Passwd"""


def init_email_info(file_name, info):
    """ 初始化-邮件信息 """
    with open(file_name, 'w', encoding='utf8') as fEmail:
        fEmail.write(info)


def format_info(file):
    """
    按需求读入文件 ->
        1. 忽略以 # 开头的行。
        2. 以 "= "为 "：" 把文件转化为字典读入程序。
        3. 忽略 # 后的所有内容。
    :param file: 文件路径
    :return: 一个字典
    """
    _f = open(file, 'r', encoding='utf8').read().split('\n')
    _info = {}
    # _f = [i for i in _f if i != ''] print(_f)
    for i1 in _f:
        i1 = i1.replace(' ', '')  # 去除头尾的制定字符串
        if i1 != '' and i1[0] != '#':
            i1 = i1[:i1.find('#')].strip(' ').strip().split('=')  # 删除 # 以后的内容 并去除空格和\t
            for x in range(0, len(i1)):
                i1[x] = i1[x].replace('"', '')
                i1[x] = i1[x].replace("'", '')
            try: _info[i1[0]] = int(i1[1])
            except ValueError: _info[i1[0]] = i1[1]
    return _info


def writeLog(file, mail, msg_):
    with open(file, 'a', encoding='gbk') as fLog:
        fLog.write(f'[{nowTime}] | ' + f'{mail}'.ljust(18) + '|' + f'{ipv4}'.center(16) + f'| {msg_}\n')


def Traceback():
    with open(f_logError, mode='a', encoding='utf8') as f_e:
        f_e.write(f'**********{nowTime}**********\n')
        f_e.write(format_exc())
        f_e.write('\n\n')


def send_email(info_email, title, msg):
    # 第三方 SMTP 服务
    emInfo = format_info(info_email)
    # print(emInfo)
    receiver = emInfo['receiver']           # 收件人 (List or Str)
    sender = emInfo['sender']               # 发件人
    mailHost = emInfo['mailHost']           # SMTP 服务器
    mailUser = emInfo['mailUser']           # User
    mailPasswd = emInfo['mailPasswd']       # Passwd

    message = MIMEText(msg, 'plain', 'utf-8')  # 创建消息实例 内容 格式（plain，html） 编码
    message['Subject'] = Header(title, 'utf-8')  # 消息的 主题或标题
    message['from'] = f'IPAddr<{sender}>'                        # 发件人
    message['to'] = receiver                        # 收件人

    try:
        smtpObj = smtplib.SMTP(host=mailHost)       # 建立SMTP链接的实例, (从3.7开始实例化需要指定Host)
        smtpObj.connect(mailHost, 25)               # 25 为 SMTP 端口号 - 链接到SMTP的服务器
        smtpObj.login(mailUser, mailPasswd)         # 登录用户
        smtpObj.sendmail(sender, receiver, message.as_string())  # 发送邮件-发件人-收件人- 消息对象
        print("邮件发送成功")
        return 0, receiver
    except smtplib.SMTPConnectError and smtplib.SMTPDataError:
        print("Error: 无法发送邮件")
        # remove(f_ipv4)
        Traceback()
        return -1, receiver


def send_IP():
    _title = f'[{nowTime}]Your New IP' + f'{ipv4}'.center(16)
    _msg = f'[{nowTime}] New ipv4 is {ipv4.center(16)}'
    _r1, _mail = send_email(f_infoEmailQq, _title, _msg)
    if _r1 == -1: _r1, _mail = send_email(f_infoEmail126, f'[{nowTime}]你的新地址', f'[{nowTime}] New ipv4  {ipv4}')
    if _r1 == 0:  open(f_ipv4, 'w', encoding='utf8').write(ipv4)
    if _r1 == 0:  writeLog(f_logSent, _mail, f'IP 更新 ')
    if _r1 == -1:  writeLog(f_logSent, _mail, f'发送失败, 查看ErrorTraceback.txt了解详情。')


def main():
    if not exists(f_infoEmail126): init_email_info(f_infoEmail126, _str126)
    if not exists(f_infoEmailQq): init_email_info(f_infoEmailQq, _strQq)
    if exists(f_logRepeat) and getsize(f_logRepeat) > 100000: remove(f_logRepeat)
    if not exists(f_ipv4) or not ipv4 == open(f_ipv4, 'r', encoding='utf8').read(): send_IP()
    else:
        writeLog(f_logRepeat, 'NoMail', 'None')
        print('Keep previous IPv4 address.')
    # elif not ipv4 == open(f_ipv4, 'r', encoding='utf8').read(): send_IP()
    # if exists('./_sup/ipv4.ini'): remove('./_sup/ipv4.ini')


if __name__ == '__main__':
    # while True:
    main()
    # time.sleep(300)